package cn.iocoder.yudao.framework.web.core.version;

import cn.iocoder.yudao.framework.web.config.WebProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.Set;

@RequiredArgsConstructor
public class ApiVersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {

    private final String basePackage;
    private final WebProperties.ApiVersion apiVersionProperties;

    @Override
    protected boolean isHandler(Class<?> beanType) {
        return super.isHandler(beanType);
    }

    @Override
    protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
        ApiVersion apiVersion = handlerType.getAnnotation(ApiVersion.class);
        return  null == apiVersion ? super.getCustomTypeCondition(handlerType) : new ApiVersionCondition(
                apiVersion.value(), apiVersion.accessPolicy());
    }

    @Override
    protected RequestCondition<?> getCustomMethodCondition(Method method) {
        ApiVersion apiVersion = method.getAnnotation(ApiVersion.class);
        return  null == apiVersion ? super.getCustomMethodCondition(method) : new ApiVersionCondition(apiVersion.value()
                , apiVersion.accessPolicy());
    }

    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo originInfo = super.getMappingForMethod(method, handlerType);
        if (originInfo == null) {
            return null;
        }
        ApiVersionParams params = null;
        // 查询是否存在方法级别的版本控制
        ApiVersion methodVersion =  AnnotationUtils.getAnnotation(method, ApiVersion.class);
        if (methodVersion != null) {
            params = ApiVersionParams.builder()
                    .apiVersionType(methodVersion.type())
                    .version(methodVersion.value())
                    .ignore(methodVersion.ignore())
                    .build();
        }
        // 如果没有方法级别的版本控制，查询是否存在控制器级别的版本控制
        ApiVersion apiVersion = AnnotationUtils.getAnnotation(handlerType, ApiVersion.class);
        if (params == null && apiVersion != null) {
            params = ApiVersionParams.builder()
                    .apiVersionType(apiVersion.type())
                    .version(apiVersion.value())
                    .ignore(apiVersion.ignore())
                    .build();
        }
        // 如果两者都不存在，查询是否存在全局版本控制控制
        if (params == null && apiVersionProperties.getGlobal().isEnable() && method.getDeclaringClass().getName().startsWith(basePackage)) {
            params = ApiVersionParams.builder()
                    .apiVersionType(apiVersionProperties.getGlobal().getDefaultApiVersionPathType())
                    .version(apiVersionProperties.getGlobal().getDefaultApiVersion())
                    .ignore(false)
                    .build();
        }
        // 如果都不存在，则返回原始的请求定义
        if (params == null || params.isIgnore()) {
            return originInfo;
        }
        return createRequestMappingInfo(params, originInfo);
    }

    private RequestMappingInfo createRequestMappingInfo(ApiVersionParams params, RequestMappingInfo originInfo) {
        return RequestMappingInfo
                .paths(params.getApiVersionType().path(params.getVersion()))
                .options(super.getBuilderConfiguration())
                .build().combine(originInfo);
    }
}